﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bridge.Workflow.Application.Contracts;
using Bridge.Workflow.Domain;
using Bridge.Workflow.Domain.Workflows;
using Bridge.Workflow.EntityFrameworkCore.Persistence;
using Bridge.Workflow.Extension;
using Bridge.Workflow.WorkflowCore;
using Bridge.Workflow.Workflows.Dtos;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Users;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using Volo.Abp.Identity;
using Volo.Abp.Uow;
using Volo.Abp.Users;
using WorkflowCore.Interface;
using WorkflowCore.Models;
using WorkflowCore.Models.DefinitionStorage.v1;
using WorkflowCore.Services.DefinitionStorage;

namespace Bridge.Workflow.Application
{
    /// <summary>
    /// 
    /// </summary>
    public class AbpWorkflowManager : DomainService, IAbpWorkflowManager
    {
        /// <summary>
        /// 
        /// </summary>
        private readonly WorkflowDefinitionManager _workflowDefinitionManager;
        private readonly IWorkflowHost _workflowHost;
        private readonly IWorkflowController _workflowService;
        private readonly IWorkflowRegistry _registry;
        private readonly IAbpPersistenceProvider _persistenceProvider;
        //private readonly ISearchIndex _searchService;
        private readonly IDefinitionLoader _definitionLoader;
        private readonly IRepository<PersistedWorkflowDefinition, string> _workflowDefinitionRepository;
        private readonly IRepository<PersistedWorkflow> _workflowRepository;
        private readonly IRepository<PersistedWorkflowAuditor> _auditRepository;
        private readonly IRepository<PersistedExecutionPointer> _pointerRepository;
        private readonly IReadOnlyCollection<AbpWorkflowStepBody> _stepBodys;
        private readonly ICurrentUser _currentUser;
        private readonly IUserService _userService;
        private readonly IAbpPersistenceProvider _abpPersistenceProvider;
        private readonly IUserAppService _userAppService;

        public AbpWorkflowManager(
            WorkflowDefinitionManager workflowDefinitionManager,
            IWorkflowHost workflowHost,
            IWorkflowController workflowService,
            IWorkflowRegistry registry,
            IAbpPersistenceProvider persistenceProvider,
            //ISearchIndex searchService,
            IDefinitionLoader definitionLoader,
            IRepository<PersistedWorkflowDefinition, string> workflowDefinitionRepository,
            IRepository<PersistedWorkflow> workflowRepository,
            ICurrentUser currentUser,
            IAbpPersistenceProvider abpPersistenceProvider,
            IUserService userService,
            IRepository<PersistedExecutionPointer> pointerRepository,
            IRepository<PersistedWorkflowAuditor> auditRepository,
            IUserAppService userAppService)
        {
            _auditRepository = auditRepository;
            _workflowDefinitionManager = workflowDefinitionManager;
            _workflowHost = workflowHost;
            _workflowService = workflowService;
            _registry = registry;
            _persistenceProvider = persistenceProvider;
            //_searchService = searchService;
            _definitionLoader = definitionLoader;
            _workflowDefinitionRepository = workflowDefinitionRepository;
            _stepBodys = _workflowDefinitionManager.GetAllStepBodys();
            _workflowRepository = workflowRepository;
            _currentUser = currentUser;
            _abpPersistenceProvider = abpPersistenceProvider;
            _userService = userService;
            _pointerRepository = pointerRepository;
            _userAppService = userAppService;
    }

        /// <summary>
        ///  初始化注册流程定义，这里是初始化所有的，如果流程定义数据集较多会存在性能问题
        /// </summary>
        [UnitOfWork]
        public virtual async Task Initialize()
        {
            var workflows = await _workflowDefinitionRepository.ToListAsync();
            foreach (var workflow in workflows)
            {
                LoadDefinition(workflow);
            }
        }

        /// <summary>
        /// 获取流程流程的节点
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<PersistedExecutionPointer> GetPersistedExecutionPointer(string id)
        {
            return await _persistenceProvider.GetPersistedExecutionPointer(id);
        }

        /// <summary>
        /// 删除流程定义
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [UnitOfWork]
        public virtual async Task DeleteAsync(string id)
        {
            var entity = await _workflowDefinitionRepository.GetAsync(id);

            var all = await _persistenceProvider.GetAllRunnablePersistedWorkflow(entity.Id, entity.Version);
            if (all.Count() > 0)
            {
                throw new UserFriendlyException("删不了！！还有没有执行完的流程！");
            }

            if (_registry.IsRegistered(entity.Id, entity.Version))
            {
                _registry.DeregisterWorkflow(entity.Id, entity.Version);
            }


            await _workflowDefinitionRepository.DeleteAsync(entity);
        }

        /// <summary>
        /// 获取所有的流程步骤
        /// </summary>
        /// <returns></returns>
        public virtual IEnumerable<AbpWorkflowStepBody> GetAllStepBodys()
        {
            return _stepBodys;
        }

        /// <summary>
        /// 发布事件订阅
        /// </summary>
        /// <param name="eventName"></param>
        /// <param name="eventKey"></param>
        /// <param name="eventData"></param>
        /// <returns></returns>
        public virtual async Task PublishEventAsync(string eventName, string eventKey, object eventData)
        {
            await _workflowHost.PublishEvent(eventName, eventKey, eventData);
        }

        /// <summary>
        /// 创建流程
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<PersistedWorkflowDefinition> CreateAsync(PersistedWorkflowDefinition entity)
        {
            return await _workflowDefinitionRepository.InsertAsync(entity, true);
        }

        /// <summary>
        /// 启动流程
        /// </summary>
        /// <param name="id"></param>
        /// <param name="version"></param>
        /// <param name="inputs"></param>
        /// <returns></returns>
        [UnitOfWork]
        public virtual async Task StartWorlflow(string id, int version, Dictionary<string, object> inputs)
        {
            try
            {

                if (!_registry.IsRegistered(id, version))
                {
                    throw new UserFriendlyException("工作流未定义!");
                }
                //节点记录
                List<PersistedExecutionPointer> pointerList = new List<PersistedExecutionPointer>();
                //审批记录
                List<PersistedWorkflowAuditor> auditorList = new List<PersistedWorkflowAuditor>();
                //创建工作流实例
                var workdef = await _workflowDefinitionRepository.FirstOrDefaultAsync(a => a.Id == id);
                PersistedWorkflow workflow = new PersistedWorkflow(GuidGenerator.Create().ToString())
                {
                    WorkflowDefinitionId = workdef.Id,
                    Version = workdef.Version,
                    Description = workdef.Title,
                    Data = JsonConvert.SerializeObject(inputs),
                    Status = WorkflowStatus.Runnable,
                    CreateUserIdentityName = _currentUser.Name,

                };
                

                //获取开始节点,生成审批记录
                var startNode = workdef.Nodes.Where(a => a.Title == OperateNameEnum.开始.ToString()).FirstOrDefault();
                //生成开始节点的pointer
                string startPointerId = GuidGenerator.Create().ToString();
                PersistedExecutionPointer startPointer = new PersistedExecutionPointer(startPointerId)
                {
                    WorkflowId = workflow.Id,
                    StartTime = DateTime.Now,
                    EndTime = DateTime.Now,
                    StepId = 2,
                    Active = true,
                    EventName = startNode.Title,
                    EventKey = startNode.Key,
                    EventPublished = true,
                    StepName = startNode.Title,
                    RetryCount = 0,
                    PredecessorId = _currentUser?.Id.ToString(),
                    Status = PointerStatus.Complete


                };
                pointerList.Add(startPointer);
                PersistedWorkflowAuditor auditor = new PersistedWorkflowAuditor(GuidGenerator.Create().ToString())
                {
                    WorkflowId = workflow.Id,
                    ExecutionPointerId = startPointerId,
                    Status = EnumAuditStatus.Pass,
                    AuditTime = DateTime.Now,

                    UserId = _currentUser?.Id ?? Guid.Empty,
                    TenantId = workflow.TenantId,
                    UserIdentityName = _currentUser.Name,
                    CreationTime = DateTime.Now,
                    Remark = OperateNameEnum.提交.ToString(),
                    CreatorId = _currentUser?.Id ?? Guid.Empty,
                };

                auditorList.Add(auditor);
                //下一个节点
                var nextNodeKey = startNode.NextNodes.FirstOrDefault()?.NodeId;
                var nextNode = workdef.Nodes.Where(a => a.Key == nextNodeKey).FirstOrDefault();
                //生成当前待审批的节点
                string nextPointerId = GuidGenerator.Create().ToString();
                PersistedExecutionPointer nextPointer = new PersistedExecutionPointer(nextPointerId)
                {
                    WorkflowId = workflow.Id,
                    StartTime = DateTime.Now,
                    StepId = 2,
                    Active = true,
                    EventName = nextNode.Title,
                    EventKey = nextNode.Key,
                    EventPublished = true,
                    StepName = nextNode.Title,
                    SourceName=startNode.Title,
                    SourceKey = startNode.Key,
                    RetryCount = 0,
                    PredecessorId = _currentUser?.Id.ToString(),
                    Status = PointerStatus.Running


                };
                pointerList.Add(nextPointer);

                //获取审批用户
                //List<IdentityUserDto> userList = GetApprovalUserList(nextNode).Result;
                List<IdentityUserDto> userList =  _userAppService.GetApprovalUserList(nextNode, workflow).Result;
                //生成待审批记录
                foreach (var user in userList)
                {
              
                    PersistedWorkflowAuditor userAudit = new PersistedWorkflowAuditor(GuidGenerator.Create().ToString())
                    {
                        WorkflowId = workflow.Id,
                        ExecutionPointerId = nextPointerId,
                        Status = EnumAuditStatus.UnAudited,
                        UserId = user.Id,
                        TenantId = workflow.TenantId,
                        UserIdentityName = user.Name,
                        CreationTime = DateTime.Now,
                        Remark = string.Empty,
                        CreatorId = _currentUser?.Id,
                    };
                    auditorList.Add(userAudit);
                }

                #region 数据持久化
                await _workflowRepository.InsertAsync(workflow);
                await _pointerRepository.InsertManyAsync(pointerList);
                await _auditRepository.InsertManyAsync(auditorList);
                #endregion
            }
            catch (Exception ex)
            {
                throw new UserFriendlyException($"发起工作流失败，原因{ex.Message}");
            }


        }

        //private async Task<List<IdentityUserDto>> GetApprovalUserList(WorkflowNode nextNode)
        //{
        //    var res = new List<IdentityUserDto>();
        //    var stepBodyName = nextNode.StepBody.Name;

        //    switch (stepBodyName)
        //    {
        //        case "FixedRoleAudit"://获取角色审批的用户
        //            var roleId = nextNode.StepBody.Inputs["RoleName"].Value?.ToString();
        //            var userIdentityName = await _userManager.WfGetAsyncById(_currentUser.Id ?? Guid.Empty);
        //            Guid agencyId = new Guid(userIdentityName.AgencyName);

        //            res = await _userManager.GetUserListByRoleName(Guid.Parse(roleId), agencyId);
                  
        //            break;
        //    }
        //    return res;
        //}

        //public virtual async Task StartWorlflow_old(string id, int version, Dictionary<string, object> inputs)
        //{
        //    if (!_registry.IsRegistered(id, version))
        //    {
        //        throw new UserFriendlyException("the workflow  has not been defined!");
        //    }

        //    await _workflowHost.StartWorkflow(id, version, inputs);
        //}

        /// <summary>
        /// 终止流程
        /// </summary>
        /// <param name="workflowId"></param>
        /// <returns></returns>
        public virtual async Task<bool> TerminateWorkflow(string workflowId)
        {
            return true;
        }
        //public virtual async Task<bool> TerminateWorkflow_old(string workflowId)
        //{
        //    return await _workflowService.TerminateWorkflow(workflowId);
        //}

        /// <summary>
        /// 更新流程定义
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public virtual async Task<PersistedWorkflowDefinition> UpdateAsync(PersistedWorkflowDefinition entity)
        {
            //判断流程定义是否注册
            if (_registry.IsRegistered(entity.Id, entity.Version))
            {
                _registry.DeregisterWorkflow(entity.Id, entity.Version);
            }

            LoadDefinition(entity);

            return await _workflowDefinitionRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 注册工作流
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public virtual WorkflowDefinition LoadDefinition(WorkflowDesignInfo input)
        {
            if (_registry.IsRegistered(input.Id, input.Version))
            {
                throw new AbpException($"工作流【{input.Title}】已被注册");
            }
            var source = new DefinitionSourceV1
            {
                Id = input.Id.ToString(),
                Version = input.Version,
                Description = input.Title,
                //定义错误重试间隔时间
                DefaultErrorRetryInterval = TimeSpan.FromSeconds(1),
                DefaultErrorBehavior = WorkflowErrorHandling.Retry,
                DataType = $"{typeof(Dictionary<string, object>).FullName}, {typeof(Dictionary<string, object>).Assembly.FullName}"
            };

            if (input.Nodes.Count(x => x.ParentNodes.IsNullOrEmpty()) > 1)
            {
                throw new AbpException("流程节点定义错误，所有节点必须串联起来！");
            }

            var startNode = input.Nodes.FirstOrDefault(x => x.ParentNodes.IsNullOrEmpty());

            //递归建立各个审批节点和分之节点
            BuildWorkflow(input.Nodes, source, _stepBodys, startNode);

            var json = source.ToJsonString();
            //Logger.DebugFormat("Workflow Json:{0}", json);

            //Console.WriteLine($"Workflow Json:{json}");

            var def = _definitionLoader.LoadDefinition(json, Deserializers.Json);

            Console.WriteLine("注册工作流！", def);
            return def;
        }

        /// <summary>
        /// 创建流程步骤
        /// </summary>
        /// <param name="allNodes">所有的步骤节点数据</param>
        /// <param name="source">流程定义数据源</param>
        /// <param name="stepBodys">具体的步骤数据</param>
        /// <param name="node">开始节点数据</param>
        protected virtual void BuildWorkflow(IEnumerable<WorkflowNode> allNodes,
            DefinitionSourceV1 source,
            IEnumerable<AbpWorkflowStepBody> stepBodys,
            WorkflowNode node)
        {
            if (source.Steps.Any(u => u.Id == node.Key))
            {
                return;
            }

            var stepSource = new StepSourceV1
            {
                Id = node.Key,
                Name = node.Title,

                //Do可以定义并行任务，用于会签
                //Do = new List<List<StepSourceV1>>()
            };

            //查询步骤的处理方式，如果没有找到，则默认使用自动处理方式
            AbpWorkflowStepBody stepbody = stepBodys.FirstOrDefault(u => u.Name == node.StepBody.Name);
            if (stepbody == null)
            {
                stepbody = new AbpWorkflowStepBody() { StepBodyType = typeof(NullStepBodyService) };
            }

            stepSource.StepType = $"{stepbody.StepBodyType.FullName}, {stepbody.StepBodyType.Assembly.FullName}";

            foreach (var input in stepbody.Inputs)
            {
                var value = node.StepBody.Inputs[input.Key].Value;
                if (!(value is IDictionary<string, object> || value is IDictionary<object, object>))
                {
                    value = $"\"{value}\"";
                }

                stepSource.Inputs.TryAdd(input.Key, value);
            }

            source.Steps.Add(stepSource);

            BuildBranching(allNodes, source, stepSource, stepBodys, node.NextNodes);
        }

        /// <summary>
        /// 创建流程分支
        /// </summary>
        /// <param name="allNodes">所有的节点数据</param>
        /// <param name="source">流程定义数据源</param>
        /// <param name="stepSource">步骤数据源</param>
        /// <param name="stepBodys">步骤数据</param>
        /// <param name="nodes">条件分之数据</param>
        protected virtual void BuildBranching(IEnumerable<WorkflowNode> allNodes,
            DefinitionSourceV1 source,
            StepSourceV1 stepSource,
            IEnumerable<AbpWorkflowStepBody> stepBodys,
            IEnumerable<WorkflowConditionNode> nodes)
        {
            foreach (var nextNode in nodes)
            {
                var node = allNodes.First(u => u.Key == nextNode.NodeId);
                stepSource.SelectNextStep[nextNode.NodeId] = "1==1";
                if (nextNode.Conditions.Count() > 0)
                {
                    var exps = new List<string>();
                    foreach (var cond in nextNode.Conditions)
                    {
                        if (cond.Value is string && (!decimal.TryParse(cond.Value.ToString(), out decimal tempValue)))
                        {
                            if (cond.Operator != "==" && cond.Operator != "!=")
                            {
                                throw new AbpException($" if {cond.Field} is type of 'String', the Operator must be \"==\" or \"!=\"");
                            }

                            exps.Add($"data[\"{cond.Field}\"].ToString() {cond.Operator} \"{cond.Value}\"");
                            continue;
                        }

                        exps.Add($"decimal.Parse(data[\"{cond.Field}\"].ToString()) {cond.Operator} {cond.Value}");
                    }

                    stepSource.SelectNextStep[nextNode.NodeId] = string.Join(" && ", exps);
                }

                BuildWorkflow(allNodes, source, stepBodys, node);
            }
        }
    }
}
